package RSAGUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.DefaultCaret;

import RSA.Key;
import RSA.RSA;

public class Interface extends JFrame implements ActionListener, ChangeListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final ArrayList<Integer> keyLengths = new ArrayList<Integer>() {
		private static final long serialVersionUID = 1L;
	{ add(64); add(128); add(256); add(512); add(1024); add(2048); add(4096);}};
	private static final int defaultKeyLength = 128;
	private JTextArea m_console;
	private JLabel m_messageLabel;
	private JLabel m_messageLabel2;
	private JTextArea m_champsmessage;
	private JTextArea m_champsmessagerecu;
	private String m_message = "";
	private JButton m_generateKey;
	private JButton m_sendKey;
	private JButton m_compare;
	private JLabel m_keyLengthLabel;
	private JSlider m_keyLengthSlider;
	
	private int m_keyLength;
	private int m_portE;
	private int m_portR;
	
	private MonSocket m_socket;
	
	private RSA m_rsa;
	
	public Interface(String l_name, int portE, int portR)
	{
		this.setTitle(l_name);
		this.setName(l_name);
		this.setSize(400, 800);
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		
		this.add(getPanel());
		
		m_keyLength = defaultKeyLength;
		m_rsa = new RSA(m_keyLength);
		
		writeln("Une nouvelle paire de clés RSA a été créée");
		writeln("Clé ("+m_rsa.getKeyLength()+" bits):\n"+m_rsa.getPublicKey().toString());
		
		m_portE = portE;
		m_portR = portR;
		
	}
	
	public void dispose()
	{
		if(m_socket!=null && m_socket.isAlive())
		{
			m_socket.interrupt();
			
			m_socket.closeAllSockets();
		}
		//System.out.println(m_socket.isAlive());
		super.dispose();
	}
	
	public JPanel getPanel()
	{
		JPanel jp = new JPanel();
		
		m_keyLengthLabel = new JLabel();
		m_keyLengthSlider = getKeyLengthSlider();
		
		m_generateKey = new JButton("Générer une paire de clés");
		m_sendKey = new JButton("Envoyer la clé publique");
		m_compare = new JButton("Comparer");
		m_compare.setEnabled(false);
		
		m_keyLengthSlider.addChangeListener(this);
		m_generateKey.addActionListener(this);
		m_sendKey.addActionListener(this);
		m_compare.addActionListener(this);
		
		m_console = new JTextArea();
		m_console.setBackground(new Color(0,0,0));
		m_console.setForeground(new Color(255,255,255));
		m_console.setEditable(false);
		
		DefaultCaret caret = (DefaultCaret) m_console.getCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		
		JScrollPane jsp = new JScrollPane(m_console);
		jsp.setPreferredSize(new Dimension(400,400));
		jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		
		//m_champsmessage = new JTextArea("Bonjour je m'appelle "+this.getName());
		m_champsmessage = new JTextArea("Voici le message à crypter");
		//m_champsmessage = new JTextArea("Out of the night that covers me,\nBlack as the pit from pole to pole,\nI thank whatever gods may be\nFor my unconquerable soul.");
		m_champsmessagerecu = new JTextArea("");
		m_champsmessagerecu.setEditable(false);
		writeln("Bonjour, bienvenue à "+this.getName());
		
		BoxLayout gl = new BoxLayout(jp,BoxLayout.Y_AXIS);
		
		m_messageLabel = new JLabel("Message a envoyer :");
		m_messageLabel2 = new JLabel("Message reçu :");
		
		
		jp.setLayout(gl);
		jp.add(jsp);
		jp.add(m_messageLabel);
		jp.add(m_champsmessage);
		jp.add(m_messageLabel2);
		jp.add(m_champsmessagerecu);
		jp.add(m_keyLengthLabel);
		jp.add(m_keyLengthSlider);
		jp.add(m_generateKey);
		jp.add(m_sendKey);
		jp.add(m_compare);
		
		return jp;
	}
	
	private JSlider getKeyLengthSlider() {
		
		JSlider keyLengthSlider = new JSlider(JSlider.HORIZONTAL,0,(keyLengths.size()-1),keyLengths.indexOf(defaultKeyLength));

		m_keyLengthLabel.setText("Taille de la clé :"+keyLengths.get(keyLengthSlider.getValue())+" bits");
		
		return keyLengthSlider;
	}

	public void writeln(String x)
	{
		write(x+"\n");
	}
	public void write(String x)
	{
		m_console.append(this.getName()+":~$ "+x);
	}
	public void write2(String x)
	{
		m_console.append(x);
	}
	
	public void writeMessageFromBytes(byte[] b)
	{
		writeln("Reception du message :");
		writeln("\""+RSA.getStringFromBytes(b)+"\"");
		writeln("Décryptage :");
		String result = RSA.getStringFromBytes(m_rsa.Decrypt(b));
		writeln("\""+result+"\"");
		
		m_message = result;
		m_champsmessagerecu.setText(result);
		m_compare.setEnabled(true);
		//m_champsmessage.setText(RSA.getStringFromBytes(m_rsa.Decrypt(b)));
		writeln("Attente d'une clé publique...("+m_portR+")");
		stopServer();
		launchServer();
	}
	
	public void sendKey(Key pubKey)
	{
		MonSocket ms = new MonSocket(m_portE, this);
		ms.send(pubKey);
		launchServer();
	}
	
	public void sendData(byte[] mess)
	{
		MonSocket ms = new MonSocket(m_portE, this);
		ms.send(mess);
	}

	public void actionPerformed(ActionEvent arg0) {
		//writeln("Le bouton '"+arg0.getActionCommand()+"' a été cliqué");
		
		if(arg0.getSource().equals(m_generateKey))
		{
			//this.;
			//m_rsa.setKeyLength(m_keyLength);
			//m_rsa.start();
			m_rsa.generateKeys(m_keyLength);
			while(m_rsa.isAlive()){ write2("."); };
			//m_rsa = new RSA(m_keyLength);
			writeln("Une nouvelle paire de clés RSA a été créée");
			writeln("Clé ("+m_rsa.getKeyLength()+" bits):\n"+m_rsa.getPublicKey().toString());
		}
		if(arg0.getSource().equals(m_sendKey))
		{
			sendKey(m_rsa.getPublicKey());
		}
		if(arg0.getSource().equals(m_compare))
		{
			compare();
		}
	}
	
	public void setPublicKey(Key Pk)
	{
		//On sauvegarde la clé publique 
		Key old = m_rsa.getPublicKey();
		//On remplace la clé publique par la clé reçue
		m_rsa.setPublicKey(Pk);
		//On annonce qu'on a reçu une clé
		writeln("Nouvelle clé publique reçue :\n"+Pk.toString());
		//On récupère le message à envoyer
		m_message = m_champsmessage.getText();
		//On précise quel message va être envoyé
		writeln("Envoie du message :\""+m_message+"\"");
		//On encrypte le message
		byte[] encryptedData = m_rsa.EncryptString(m_message);
		//On restaure l'ancienne clé
		m_rsa.setPublicKey(old);
		//On envoie le message codé
		
		stopServer();
		
		sendData(encryptedData);
	}
	
	public void launchServer()
	{
		//m_socket = null;
		//m_generateKey.setEnabled(false);
		m_sendKey.setEnabled(false);
		m_socket = new MonSocket(m_portR,this);
		m_socket.start();
		
	}
	
	public void stopServer()
	{
		//m_generateKey.setEnabled(true);
		m_sendKey.setEnabled(true);
		//
		//System.out.println(m_socket.isInterrupted());
		m_socket.closeAllSockets();
		m_socket.interrupt();
		m_socket = null;
	}

	public void compare()
	{
		String send, recieved;
		
		send = m_champsmessage.getText();
		recieved = m_champsmessagerecu.getText();
		
		if(send.equals(recieved))
		{
			writeln("Les messages sont identiques");
		}
		else
		{
			writeln("Les messages sont différents");
			//writeln("|"+send+"|"+send.length());
			//writeln("|"+recieved+"|"+recieved.length());
			//byte[] b = recieved.getBytes();
			//for(int i=0; i<b.length;i++) write(b[i]+"");
			//writeln("");
			//b = send.getBytes();
			//for(int i=0; i<b.length;i++) write(b[i]+"");
		}
	}
	
	public void stateChanged(ChangeEvent e) {
		
		if(e.getSource().getClass().equals(JSlider.class))
		{
			m_keyLengthLabel.setText("Taille de la clé :"+keyLengths.get(m_keyLengthSlider.getValue())+" bits");
			m_keyLength = keyLengths.get(m_keyLengthSlider.getValue());
		}
	}

}
